package test


import src._
import spinal.core.sim._
import spinal.core.sim.SimConfig
import spinal.core.{SFix, Vec, _}
import test.ParallelSRCTest.N
object SrcSim {
  val coefficientConst = Array[Double](
    //-0.00152884475502033, -0.00190413765156085, -0.00251201020053917, -0.00315172285923541, -0.00338157483002662, -0.00256899869677061, 1.4330398689852E-18, 0.00497037076557457, 0.0127558532986817, 0.023399631051306, 0.036490180152569, 0.0511553725692717, 0.0661431077396454, 0.0799794721992498, 0.0911792726013163, 0.0984722196424889, 0.101003617946099, 0.0984722196424889, 0.0911792726013163, 0.0799794721992498, 0.0661431077396454, 0.0511553725692717, 0.036490180152569, 0.023399631051306, 0.0127558532986817, 0.00497037076557457, 1.4330398689852E-18, -0.00256899869677061, -0.00338157483002662, -0.00315172285923541, -0.00251201020053917, -0.00190413765156085, -0.001528845
    //-0.00697814394109520, -0.0103696475300266, 0.00102743170269111, 0.0383281059702203, 0.0999719193228679, 0.166999478464426, 0.211020856010917, 0.211020856010917, 0.166999478464426, 0.0999719193228679, 0.0383281059702203, 0.00102743170269111, -0.0103696475300266, -0.00697814394109520
    //-0.00306200334634002,	-0.00503110836782698,	-0.00677269121762658,	2.87012324819924E-18,	0.0255476989130046,	0.0730833221416457,	0.132472846946078,	0.182615819497229,	0.202292230867672,	0.182615819497229,	0.132472846946078,	0.0730833221416457,	0.0255476989130046,	2.87012324819924E-18,	-0.00677269121762658,	-0.00503110836782698,	-0.003062003
    -0.000262862825969905,	6.11523137053542e-05,	0.000565590346895291,0.00146095565006740,	0.00296270382571987,	0.00526470907677153,	0.00851291268392641,	0.0127821473845232	,0.0180589041703863	,0.0242322593883240	,0.0310943652433647	,0.0383509117688612	,0.0456409012211598	,0.0525640550027438	,0.0587133135993919	,0.0637092900253034	,0.0672332672398216,	0.0690554238850042	,0.0690554238850042,	0.0672332672398216,	0.0637092900253034,	0.0587133135993919,	0.0525640550027438	,0.0456409012211598	,0.0383509117688612	,0.0310943652433647	,0.0242322593883240	,0.0180589041703863	,0.0127821473845232	,0.00851291268392641	,0.00526470907677153,	0.00296270382571987,	0.00146095565006740,	0.000565590346895291,	6.11523137053542e-05,	-0.000262862825969905
  )

  val C : Int = 16
  val L : Int = 4
  val rate : Double = 4
  def main(args: Array[String]) {
    SimConfig.withWave.withConfig(SpinalConfig(
      defaultClockDomainFrequency = FixedFrequency(100 MHz),
      defaultConfigForClockDomains = ClockDomainConfig(resetKind = SYNC))).compile(new ArbitrarySamplingRateConverse(coefficientConst.length / L,8, rate, coefficientConst)
    )
      .doSim { dut =>
        //Fork a process to generate the reset and the clock on the dut
        dut.clockDomain.forkStimulus(period = 10)
        dut.io.input.payload #= 0
        //dut.io.coefficient.ready #= true
        dut.io.input.valid #= true
        dut.io.accuracyFactor #= C
        dut.io.accumShiftBits #= (Math.log(C.toDouble / L.toDouble) / Math.log(2)).toInt
        if(rate > 1)
          dut.io.deltaInt #= C.toDouble / rate
        else
          dut.io.deltaInt #= C.toDouble * rate
        val subFilterFactor = Array.ofDim[Double](L, coefficientConst.length / L)
        var subFilterSum = new Array[Double](L)
        dut.clockDomain.waitSampling(10)
        //val subFilterFactor = Vec(Vec(SFix(0 exp, 16 bits), coefficientConst.length / L), L)
        for (i <- 0 until L) {
          subFilterSum(i) = 0
          for (j <- 0 until coefficientConst.length / L) {
            subFilterSum(i) = subFilterSum(i) + coefficientConst(j * L + i)
            subFilterFactor(i)(j) = coefficientConst(j * L + i)
          }
        }
        for (i <- 0 until L) {
          for (j <- 0 until coefficientConst.length / L) {
            subFilterFactor(i)(j) = coefficientConst(j * L + i)
          }
        }
        for(i <- 0 until L){
          subFilterFactor(i) =  subFilterFactor(i)
        }
        var filterShiftReg = new Array[Double](coefficientConst.length)
        var filterResult: Double = 0
        for (i <- 0 until coefficientConst.length) {
          filterShiftReg(i) = 0
        }

        //Drive the dut inputs with random values
        for (i <- 0 until 2000) {
//          dut.io.coefficient.valid #= true
//          for (j <- 0 until coefficientConst.length - 1) {
//            filterShiftReg(j + 1) = filterShiftReg(j)
//          }
//          if(rate >= 1)
//            for (i <- 0 until coefficientConst.length / L) {
//              dut.io.coefficient.payload(i) #= subFilterFactor(dut.io.coefficientAddress.toInt)(i)/subFilterSum(dut.io.coefficientAddress.toInt)
//            }
//          else
//            for (i <- 0 until coefficientConst.length / L) {
//              dut.io.coefficient.payload(i) #= subFilterFactor(dut.io.coefficientAddress.toInt)(i)
//            }
          if(i % rate == 0)
            filterShiftReg(0) = Math.pow(2, 6) * (Math.sin(i.toDouble / 100.0 * Math.PI))
          dut.io.input.payload #= filterShiftReg(0)
          dut.clockDomain.waitRisingEdge()
        }
      }
  }
}
